package com.shsoft.util;

import com.shsoft.config.PCStatusConstant;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.LongByReference;


public class WinRing0Util {

    static WR0 WR0_INSTANCE = Native.loadLibrary("WinRing0x64", WR0.class);
    static LongByReference eax = new LongByReference();
    static LongByReference edx = new LongByReference();


    public static void DeinitializeOls() {
        WR0_INSTANCE.DeinitializeOls();
    }


    public static int InitializeOls() {
        WR0_INSTANCE.InitializeOls();
        return WR0_INSTANCE.GetDllStatus();
    }


    public static int getCpuTemperature(){
        WR0_INSTANCE.Rdmsr(PCStatusConstant.IA32_THERM_STATUS, eax, edx);
        int IAcore = (int) ((eax.getValue() >> 16) & 0xff);
        WR0_INSTANCE.Rdmsr(PCStatusConstant.MSR_TEMPERATURE_TARGET, eax, edx);
        int TjMax = (int) ((eax.getValue() >> 16) & 0xff);
        return (TjMax - IAcore);
    }


    public static long getCpuEnergy(){
        WR0_INSTANCE.Rdmsr(PCStatusConstant.MSR_PKG_ENERGY_STATUS, eax, edx);
        return eax.getValue();
    }


    public static float getCpuEnergyUnit(){
        WR0_INSTANCE.Rdmsr(PCStatusConstant.MSR_RAPL_POWER_UNIT, eax, edx);
        int energyUnit = 1 << ((eax.getValue() >> 8) & 0x1f);
        return 1.0f / energyUnit;
    }

    public static long getPerfStatus(){
        WR0_INSTANCE.Rdmsr(PCStatusConstant.IA32_PERF_STATUS, eax, edx);
        return (eax.getValue() >> 8) & 0xff;
    }


    public static long Rdtsc(){
        WR0_INSTANCE.Rdtsc(eax, edx);
        return (edx.getValue() << 32) | eax.getValue();
    }


    private interface WR0 extends Library {
        boolean InitializeOls();

        int DeinitializeOls();

        int GetDllStatus();

        boolean Rdmsr(long index, LongByReference eax, LongByReference edx);

        boolean Rdtsc(LongByReference eax, LongByReference edx);

    }

}
